import React from 'react';
import { inject, observer, Provider } from 'mobx-react';
import { toJS } from 'mobx';
import { transportStore } from '../../store/index';
import { WeaUpload, WeaNewScroll, WeaLocaleProvider } from 'ecCom';
import { Icon, Progress, Popconfirm, Tooltip, Modal } from 'antd';
import DocNoData from '../noData';
import NativeUpload from './nativeUpload';
import { getFileIcon, onDelegate, offDelegate } from '../../../util';
import '../../style/transportList.less';

const getLabel = WeaLocaleProvider.getLabel;
const confirm = Modal.confirm;

/*
* 属性：
*  iconType        【可选 string】 图标类型。【默认值："svg"。可选值："img"】
*  historyData     【可选 array-object】 上传历史数据
*  clickUnrelated  【可选 boolean 默认true】点击无关的地方，是否收起传输框
*  removeHistory   【可选 function】删除历史记录的回调 【返回值：false表示禁止删除】
*  startUpload     【可选 function】开始上传的回调【参数：rawData来自组件库的原始数据, advice本组件整理好的数据】
*  uploadSuccess   【可选 function】上传完成的回调【参数：rawData来自组件库的原始数据, advice本组件整理好的数据】【返回值：promise对象，非必须。表示调API是否成功。如果失败，将会不断触发回调，直到成功为止】
*  cancelUpload    【可选 function】取消上传的回调【参数：rawData, advice】 加入断点续传后，可能会两个参数数量不一致【返回值：同上】
*  uploadError     【可选 function】上传异常的回调【参数：data】
*  callBackExceptTimes 【可选 number】连续触发回调的次数。用于配合返回promise对象的回调。当回调返回失败的promise时，该回调将会不断地触发，此属性用于设置此情况下触发次数的上限。默认值：10
*
*  nowPath         【可选 array-object or object】当前所在目录路径, 受控数据。数据结构与historyData元数据中的path相同
*  clickFolder     【可选 function】点击文件目录名称的事件，用于业务跳转目录【参数：path(同DocFilePath组件元数据)】
*  scrollHeight    【非必填 number】滚动条高度。不传参将默认适应组件高度
*  className
*  style
*
*  通过ref调用（在throwMethod属性内）
*  .uploadFile()    【function】点击上传文件
*
   historyData: [
      {
         fileid: "5",            【必需 string】文件ID
         filename: "",           【必需 string】文件全名
         filesize: "",           【必需 string】文件大小
         status: "",             【必需 string】状态 success、exception(取消)、fail(失败)、active、pause
         percent: 35,            【条件必需 number】上传百分比 当status为active时，必需有该字段
         datetime："",           【非必需 string】上传时间

         path:                   【必需 array-object or object】文件所在路径，从根目录开始算起。如果是根目录则为空。
         [   array-object示例
            {
               id:      // 目录id
               text:    // 目录名称
            }
         ],
         { id, text } object示例
      },
      ...
   ]
*
* */

@inject('transportStore')
@observer
class TransportList extends React.Component {
   static defaultProps = {
      iconType: 'svg',
      nowPath: [],
      historyData: [],
      removeHistory: null,
      startUpload: null,
      cancelUpload: null,
      uploadError: null,
      uploadSuccess: null,
      clickFolder: null,
      clickUnrelated: true,
      callBackExceptTimes: 10,
   };

   constructor(props) {
      super(props);
      const { setFrameData } = this.props.transportStore;
      const { clickFolder, historyData } = this.props;
      setFrameData({ data: [...historyData], canJump: typeof clickFolder === 'function', countAll: historyData.length });
      // 重复触发的回调
      this.reSendCallBack = {
         uploadSuccessBack: this.reSend_uploadSuccess, // 上传成功的回调
      };
      // 触发的次数
      this.reSendTimes = {
         uploadSuccessBack: 0,
      };
      this.toggleSelector = '.WeaDoc-TransportList, .ant-popover-inner, .ant-modal-wrap';
   }

   componentWillReceiveProps(nextProps, nextContext) {
      console.log('transportList', toJS(nextProps.nowPath));
      const { setFrameData } = this.props.transportStore;
      const { clickFolder, historyData } = this.props;
      setFrameData({ data: [...historyData], canJump: typeof clickFolder === 'function', countAll: historyData.length });
   }

   componentDidMount() {
      const { clickUnrelated } = this.props;
      const body = window.document.getElementsByTagName('BODY')[0];
      clickUnrelated && onDelegate('click', body, this.toggleSelector, this.clickUnrelated, {}, true);
      this.didMountResendAPI(); // 重复发送失败的API
   }

   componentWillUnmount() {
      const { clickUnrelated } = this.props;
      const body = window.document.getElementsByTagName('BODY')[0];
      clickUnrelated && offDelegate('click', body, this.toggleSelector, this.clickUnrelated, true);
   }

   // 点击传输框外的地方，收起传输框
   clickUnrelated = (e) => {
      const { isFold } = this.props.transportStore.frameData;
      // 当 没点中传输框 且 没折叠时 折叠传输框
      !isFold && this.toggleTransportFrame(null, true);
   };

   // 折叠传输框
   toggleTransportFrame = (e, aim) => {
      const { setFrameData, frameData } = this.props.transportStore;
      let value = aim === undefined ? !frameData.isFold : aim;
      setFrameData({ isFold: value });
   };

   // 重复发送失败的回调
   didMountResendAPI = () => {
      const uploadSuccess = JSON.parse(localStorage.getItem('NetDisk-UploadSuccess-Api'));
      if (uploadSuccess) {
         for (let i in uploadSuccess) {
            if (Object.prototype.hasOwnProperty.call(uploadSuccess, i)) {
 this.reSendCallBack.uploadSuccessBack(uploadSuccess[i][0], uploadSuccess[i][1]); 
}
         }
      }
   };

   // 取消所有确认框
   cancelAll = () => {
      confirm({
         title: getLabel(131329, '信息确认'),
         content: getLabel(386786, '确定要取消所有上传吗？'),
         onOk: () => {
            this.cancelAllUpload();
         },
      });
   };
   // 取消所有上传
   cancelAllUpload = () => {
      const { frameData } = this.props.transportStore;
      let cancelData = toJS(frameData.data).filter(i => ['active', 'pause'].includes(i.status));
      let ids = [],
advice = [];
      cancelData.forEach((i) => {
 ids.push(i.fileid); advice.push({ ...i, status: 'exception' }); 
});
      this.interruptUpload(ids, advice); // 取消上传
   };

   // 取消单个上传
   cancelUpload = (id) => {
      const { frameData } = this.props.transportStore;
      const advice = { ...toJS(frameData.data).find(f => f.fileid === id), status: 'exception' };
      this.interruptUpload([id], [advice]); // 取消上传
   };

   // 中断上传
   interruptUpload = (ids = [], advice = []) => {
      const { cancelUpload } = this.props;
      const { changeStatus } = this.props.transportStore;
      const isBatch = ids.length > 1;
      const listB = this.weaUploadRef.state.listB;
      let newListB = isBatch ? [] : listB.filter(f => ids[0] !== f.id);
      let cancelData = isBatch ? listB.filter(f => ids.includes(f.id)) : [listB.find(f => ids[0] === f.id)];
      isBatch && listB.forEach((f) => {
 this.weaUploadRef.uploader && this.weaUploadRef.uploader.removeFile(f.id); 
});
      !isBatch && this.weaUploadRef.uploader && this.weaUploadRef.uploader.removeFile(ids[0]);
      this.weaUploadRef.setState({ listB: newListB });
      changeStatus(ids, 'exception'); // 改变状态
      typeof cancelUpload === 'function' && cancelUpload(cancelData, advice);
   };

   // 删除历史记录
   removeHistory = (id) => {
      const { setFrameData, frameData } = this.props.transportStore;
      const { removeHistory } = this.props;
      let userControl;
      typeof removeHistory === 'function' && (userControl = removeHistory(id));
      if (userControl !== false) {
         let index = toJS(frameData.data).findIndex(f => f.fileid === id);
         let newData = [...toJS(frameData.data)]; newData.splice(index, 1);
         setFrameData({ data: newData });
      }
   };

   // 组件库onUploading回调
   onUploading = (status) => {
      const { setFrameData } = this.props.transportStore;
      console.log('onUploading', status);
      status === 'false' && !window.startUploadAll();
      // 改变"全部取消"的可点击状态
      if (status === 'uploading') setFrameData({ cancelAll: false });
      else setFrameData({ cancelAll: true });
   };
   // 组件库onChange回调
   upLoadChange = (ids, list) => {
      console.log('onChange', ids, list);
   };
   // 组件库getShowListDatas回调
   getShowListDatas = (already, uploading) => {
      // this.weaUploadRef && console.log("此时此刻", this.weaUploadRef.state.listB, this.weaUploadRef.state.listT);
      // console.log("getShowListDatas", already, uploading);
      const { startUpload, uploadError, nowPath } = this.props;
      const { setFrameData, frameData, changeStatus } = this.props.transportStore;
      let weaNewData = [],
addData = [],
loadingData = [...toJS(frameData.data)];
      const oldIDS = loadingData.map(i => i.fileid);


      // 新增、更新正在上传的状态
      uploading.forEach((i) => {
         if (!(oldIDS.includes(i.id) || oldIDS.includes(String(i.fileid)))) {
            let metaData = {
               fileid: i.id,
               filename: i.name,
               filesize: this.transSize(i.size, 'size'),
               path: nowPath,
               status: 'active',
               percent: i.progress,
               prevTime: (new Date()).getTime(),
               prevLoaded: 0,
               speed: 0,
            };
            addData.push(metaData); weaNewData.push(i);
         } else {
            loadingData.forEach((j) => {
               if ((j.fileid === i.fileid) || (j.fileid === i.id)) {
                  // j.filename.includes("nginx") && console.log("nginx", j, i);
                  let time = (new Date()).getTime();
                  if (i.WEA_NATIVE_FILE && i.WEA_NATIVE_FILE.loaded >= j.prevLoaded) {
                     // j.filename.includes("nginx") && console.log("已加载的", i.WEA_NATIVE_FILE.loaded, j.prevLoaded);
                     let loaded = i.WEA_NATIVE_FILE.loaded;
                     loaded >= j.prevLoaded && (j.percent = i.progress);
                     const interval = (loaded - j.prevLoaded) / ((time - j.prevTime) / 1000);
                     j.speed = this.transSize(interval, 'speed', 0);
                     j.prevTime = time; j.prevLoaded = loaded;
                  }
                  i.fileid && (j.fileid = String(i.fileid));
               }
            });
         }
         if (i.error) {
            loadingData.forEach((j) => {
 j.fileid === i.id && (j.status = 'fail'); 
});
            typeof uploadError === 'function' && uploadError(i);
         }
      });
      let unloaded = [...addData, ...loadingData];
      addData.length > 0 && typeof startUpload === 'function' && startUpload(weaNewData, addData); // 开始上传

      // 上传完成的项目
      already && already.forEach((i) => {
         if (oldIDS.includes(i.id) || oldIDS.includes(String(i.fileid))) {
            let advice;
            unloaded.forEach((j) => {
 j.fileid === String(i.fileid) && (advice = j) && (j.datetime = i.uploaddate); 
});
            // 上传成功，回调
            this.reSendCallBack.uploadSuccessBack(i, advice);
         }
      });
      setFrameData({ data: unloaded });
      // console.log("data", addData, toJS(frameData.data));
   };

   // 上传成功的回调
   reSend_uploadSuccess = (rawData, advice) => {
      const { uploadSuccess, callBackExceptTimes } = this.props;
      const { changeStatus } = this.props.transportStore;
      let apiStatus;
      const local = JSON.parse(localStorage.getItem('NetDisk-UploadSuccess-Api'));

      this.reSendTimes.uploadSuccessBack += 1;
      if (this.reSendTimes.uploadSuccessBack >= callBackExceptTimes) return;

      advice.status === 'active' && typeof uploadSuccess === 'function' && (apiStatus = uploadSuccess(rawData, advice));
      advice.status === 'active' && apiStatus && apiStatus.then && apiStatus.then((data) => {
         const listT = this.weaUploadRef.state.listT;
         this.weaUploadRef.setState({ listT: listT.filter(f => f.id !== rawData.id) }); // 清除组件库数据
         changeStatus([String(rawData.fileid)], 'success'); // 改变状态
         if (local && local.hasOwnProperty(rawData.fileid)) {
            let newLocal = { ...local }; delete newLocal[rawData.fileid];
            localStorage.setItem('NetDisk-UploadSuccess-Api', JSON.stringify(newLocal));
         }
      }, (err) => {
         if (local === null) {
            let newLocal = { [rawData.fileid]: [rawData, advice] };
            localStorage.setItem('NetDisk-UploadSuccess-Api', JSON.stringify(newLocal));
         } else {
            let newLocal = { ...local, [rawData.fileid]: [rawData, advice] };
            !local.hasOwnProperty(rawData.fileid) && localStorage.setItem('NetDisk-UploadSuccess-Api', JSON.stringify(newLocal));
         }
         this.reSend_uploadSuccess(rawData, advice);
      });
   };

   // 转换文件大小 字节 -> 合适的单位【参数：number被转换的数字, type转换类型, digit精度】
   transSize = (number, type, digit = 2) => {
      let string = '';
      let time = type === 'size' ? '' : '/S';
      switch (true) {
         case number < 1024:
            string = `${number.toFixed(digit)}B${time}`;
            break;
         case number >= 1024 && number < 1024 * 1024:
            string = `${(number / 1024).toFixed(digit)}KB${time}`;
            break;
         case number >= 1024 * 1024 && number < 1024 * 1024 * 1024:
            string = `${(number / (1024 * 1024)).toFixed(digit)}MB${time}`;
            break;
         case speed >= 1024 * 1024 * 1024:
            string = `${(number / (1024 * 1024 * 1024)).toFixed(digit)}GB${time}`;
            break;
         default:
            string = `${number.toFixed(digit)}B${time}`;
            break;
      }
      return string;
   };

   // 上传文件【对外暴露的功能】
   uploadFile = () => {
      const button = this.weaUploadRef.refs.wrap.querySelector('span.button');
      button.click();
      this.toggleTransportFrame(null, false);
   };

   render() {
      const { frameData } = this.props.transportStore;
      const { isFold, cancelAll, data, canJump, countUp, countAll } = toJS(frameData);
      const { iconType, className, style, clickFolder, scrollHeight } = this.props;

      return (
         <div className={`WeaDoc-TransportList${isFold ? ' fold' : ''} ${className || ''}`} style={style}>
            <div className={'Transport-Top'} onClick={this.toggleTransportFrame}>
               <h3>{getLabel(514014, '正在上传')} :&nbsp;&nbsp;{countUp}/{countAll}</h3>
               <div className="icon-group">
                  { isFold ? <i className="icon-coms-Loss" /> : <i className="square" /> }
               </div>
            </div>
            <ul className="Transport-Body" ref={(e) => {
 this.ulDom = e; 
}}>
               <WeaNewScroll ecId={`${this && this.props && this.props.ecId || ''}_WeaNewScroll@fixheh`} height={typeof scrollHeight === 'number' ? scrollHeight : null} style={{ height: '100%' }}>
                  {
                     data.length === 0
                        ?
                        <DocNoData ecId={`${this && this.props && this.props.ecId || ''}_DocNoData@c14hem`} text={getLabel(129227, '暂无上传')} />
                        :
                        data.map(i =>
                           (<Item ecId={`${this && this.props && this.props.ecId || ''}_Item@f53x5t@${i.fileid}`}
                             key={i.fileid}
                             data={i}
                             removeHistory={this.removeHistory}
                             iconType={iconType}
                             canJump={canJump}
                             clickFolder={clickFolder}
                             cancelUpload={this.cancelUpload}
                           />),
                        )
                  }
               </WeaNewScroll>
            </ul>
            <div className="Transport-Bottom">
               <div className="operate">
                  <WeaUpload ecId={`${this && this.props && this.props.ecId || ''}_WeaUpload@hd35mt`}
                    ref={(e) => {
 this.weaUploadRef = e; 
}}
                     // useDefaultListB
                    viewAttr={2}
                    autoUpload={false} // 自动上传
                    multiSelection={true} // 多选文件
                    uploadUrl="/api/doc/upload/uploadFile"
                    category="netDisk" // 文件上传目录 ？
                     // uploadParams={{}}
                    getShowListDatas={this.getShowListDatas}
                    onChange={this.upLoadChange}
                    onUploading={this.onUploading}
                  >
                     <span className="button"><i className="icon-coms-upload" />{getLabel(20800, '添加文件')}</span>
                  </WeaUpload>
               </div>
               <div className="operate">
                  <span className={`button${cancelAll ? ' disabled' : ''}`} onClick={!cancelAll && this.cancelAll}><Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@dkixr2`} type="cross" />{getLabel(129226, '全部取消')}</span>
               </div>
            </div>
         </div>
      );
   }
}


@inject('transportStore')
@observer
class Item extends React.Component {
   constructor(props) {
      super(props);
      const { filename } = this.props.data;
      this.state = {
         fileIcon: getFileIcon('file', filename, 'thumbnail', this.props.iconType),
         parentName: this.getparentName(),
      };
      this.timing = null;
      this.speed = null;
   }

   componentWillReceiveProps(nextProps, nextContext) {
      const nextData = nextProps.data;
      clearTimeout(this.timing);
      if (nextData.speed) {
         this.speed = nextData.speed;
         this.timing = setTimeout(() => {
 this.speed = '0KB/S'; this.forceUpdate(); 
}, 650);
      } else {
         this.timing = null;
         this.speed = null;
      }
   }

   // 根据path获取parentName
   getparentName = () => {
      const path = this.props.data.path;
      let dataType = '';
      let name = getLabel(513977, '根目录');
      // 判断path数据类型
      path instanceof Array && (dataType = 'array');
      dataType === '' && path instanceof Object && (dataType = 'object');
      // 修改name值
      dataType === 'array' && path.length !== 0 && (name = path[path.length - 1].text);
      dataType === 'object' && (name = path.text);

      return name;
   };

   // 取消上传
   confirmRemove = () => {
      const { cancelUpload, data } = this.props;
      cancelUpload(data.fileid);
   };
   // 删除历史记录
   removeHistory = () => {
      const { removeHistory, data } = this.props;
      typeof removeHistory === 'function' && removeHistory(data.fileid);
   };

   // 获取状态
   getStatusText = () => {
      const { data } = this.props;
      let text = '';
      switch (data.status) {
         case 'active':
            text = `${data.percent}%${this.speed ? ` - ${this.speed}` : ''}`;
            break;
         case 'exception':
            text = getLabel(514013, '已取消');
            break;
         case 'success':
            text = getLabel(514001, '上传成功');
            break;
         case 'fail':
            text = getLabel(25389, '上传失败');
            break;
         case 'pause':
            text = getLabel(514439, '暂停中');
            break;
         default:
            break;
      }
      return text;
   };

   // 跳转目录
   jumpFolder = () => {
      const { clickFolder, data } = this.props;
      typeof clickFolder === 'function' && clickFolder(data.path);
   };
   // 组件库tooltip相关
   getTipCon = triggerNode => triggerNode.parentNode;

   render() {
      const { fileIcon, parentName } = this.state;
      const { iconType, data, canJump } = this.props;
      const { filename, filesize, percent, status: tranStatus } = data;

      return (
         <li className={`Transport-Item ${tranStatus}`}>
            <Progress ecId={`${this && this.props && this.props.ecId || ''}_Progress@8ki6za`} percent={percent} strokeWidth={49} showInfo={false} status={tranStatus} />
            <div className="content">
               <Tooltip ecId={`${this && this.props && this.props.ecId || ''}_Tooltip@mdnv7p`} placement="bottomLeft" title={filename} getTooltipContainer={a => this.getTipCon(a).parentNode} arrowPointAtCenter>
                  {
                     iconType === 'svg'
                        ?
                           <i className={`${fileIcon.icon} file-icon c`} style={{ color: fileIcon.color }} />
                        :
                     iconType === 'img'
                        ?
                           <img className="file-icon c" src={fileIcon} alt draggable={false} />
                        :
                           null
                  }
               </Tooltip>
               <div className="file-name">
                  <Tooltip ecId={`${this && this.props && this.props.ecId || ''}_Tooltip@buh5ly`} placement="bottom" title={filename} getTooltipContainer={this.getTipCon}>
                     <span>{ filename }</span>
                  </Tooltip>
               </div>
               <Tooltip ecId={`${this && this.props && this.props.ecId || ''}_Tooltip@3rsod9`} placement="bottom" title={parentName} getTooltipContainer={a => this.getTipCon(a).parentNode}>
                  <div className={`aim-folder c${canJump ? ' jump' : ''}`} onClick={this.jumpFolder}>{ parentName }</div>
               </Tooltip>
               <div className="file-size c">{ filesize }</div>
               <div className="file-status c">
                  { this.getStatusText() }
                  {
                     tranStatus === 'success'
                        ?
                        <i className="icon-coms-Upload-successfully-o" />
                        :
                     tranStatus === 'exception'
                        ?
                        <Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@hjm4e0`} type="cross-circle" />
                        :
                     tranStatus === 'fail'
                        ?
                        <Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@021kv5`} type="cross-circle" />
                        :
                        null
                  }
               </div>
               <div className="file-operate c">
                  {
                     tranStatus === 'active'
                        ?
                        <Popconfirm ecId={`${this && this.props && this.props.ecId || ''}_Popconfirm@mzuc1z`} title={<div>{getLabel(513991, '确定取消上传吗？')}</div>} onConfirm={this.confirmRemove}>
                           <Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@y3czav`} type="cross" />
                        </Popconfirm>
                        :
                        <Tooltip ecId={`${this && this.props && this.props.ecId || ''}_Tooltip@8stv32`} placement="right" title={getLabel(513992, '清除记录')} getTooltipContainer={this.getTipCon}>
                           <Icon ecId={`${this && this.props && this.props.ecId || ''}_Icon@x8pz0a`} type="cross" onClick={this.removeHistory} />
                        </Tooltip>
                  }
               </div>
            </div>
         </li>
      );
   }
}


class WeaDocTransportList extends React.Component {
   componentDidMount() {
      const ref = this.external.wrappedInstance;
      this.throwMethod = {
         uploadFile: ref.uploadFile,
      };
   }

   render() {
      return (
         <Provider ecId={`${this && this.props && this.props.ecId || ''}_Provider@y4zslu`} transportStore={transportStore}>
            <TransportList ecId={`${this && this.props && this.props.ecId || ''}_TransportList@vkxr5g`} {...this.props} ref={(e) => {
 this.external = e; 
}} />
         </Provider>
      );
   }
}

export default WeaDocTransportList;

